import smtplib
import ssl
import schedule
import time
import requests
from datetime import datetime, timedelta
from email.header import Header
from email.utils import formataddr


class WeatherConfig:
    # Open-Meteo 配置（无需API密钥）
    LATITUDE = 31.2304  # 上海纬度
    LONGITUDE = 121.4737  # 上海经度
    TIMEZONE = "Asia/Shanghai"

    # 邮箱配置（QQ邮箱示例）
    SMTP_SERVER = "smtp.qq.com"
    SMTP_PORT = 465
    EMAIL_USER = "1601584267@qq.com"  # 发件邮箱
    EMAIL_PASSWORD = "ebxsawqjwwxwiccf"  # 邮箱授权码
    RECEIVER_EMAIL = "1601584267@qq.com"  # 收件邮箱


class WeatherMonitor:
    def __init__(self):
        self.config = WeatherConfig()
        self.ssl_context = ssl.create_default_context()
        self.ssl_context.set_ciphers("DEFAULT@SECLEVEL=1")

        # Open-Meteo API 端点
        self.API_URL = "https://api.open-meteo.com/v1/forecast"

    def get_weather_data(self):
        """获取Open-Meteo天气数据"""
        params = {
            "latitude": self.config.LATITUDE,
            "longitude": self.config.LONGITUDE,
            "hourly": "temperature_2m,precipitation_probability,weathercode",
            "daily": "weathercode,temperature_2m_max,temperature_2m_min",
            "timezone": self.config.TIMEZONE,
            "forecast_days": 2  # 获取今天和明天数据
        }

        try:
            response = requests.get(self.API_URL, params=params, timeout=10)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            print(f"获取天气数据失败: {str(e)}")
            return None

    def parse_weather(self, api_data):
        """解析Open-Meteo数据格式"""
        if not api_data:
            return None

        # 获取明天数据（索引1为明天）
        tomorrow = (datetime.now() + timedelta(days=1)).date().isoformat()

        # 解析白天数据（假设早晨时间为6-9点）
        morning_hours = [h for h in api_data["hourly"]["time"]
                         if h.startswith(tomorrow)
                         and 6 <= int(h[-5:-3]) < 10]

        morning_data = {
            "precip_prob": max(
                api_data["hourly"]["precipitation_probability"][i]
                for i, t in enumerate(api_data["hourly"]["time"])
                if t in morning_hours
            ),
            "weathercode": api_data["daily"]["weathercode"][1],  # 天气代码
            "temp_max": api_data["daily"]["temperature_2m_max"][1],
            "temp_min": api_data["daily"]["temperature_2m_min"][1]
        }

        return {
            "date": tomorrow,
            "condition": self._weathercode_to_text(morning_data["weathercode"]),
            "precip_prob": morning_data["precip_prob"],
            "temp_range": f"{morning_data['temp_min']}~{morning_data['temp_max']}℃"
        }

    def _weathercode_to_text(self, code):
        """天气代码转换（简化版）"""
        WEATHER_MAP = {
            0: "晴", 1: "多云", 2: "阴", 3: "多云",
            45: "雾", 48: "冻雾",
            51: "小雨", 53: "中雨", 55: "大雨",
            56: "冻雨", 57: "大冻雨",
            61: "小雨", 63: "中雨", 65: "大雨",
            66: "冰雹", 67: "大冰雹",
            71: "小雪", 73: "中雪", 75: "大雪",
            77: "冰雹", 80: "暴雨", 81: "大暴雨", 82: "特大暴雨"
        }
        return WEATHER_MAP.get(code, "未知天气")

    def send_email(self, subject, body):
        """发送邮件（支持UTF-8）"""
        try:
            with smtplib.SMTP_SSL(
                    self.config.SMTP_SERVER,
                    self.config.SMTP_PORT,
                    context=self.ssl_context
            ) as server:
                server.login(self.config.EMAIL_USER, self.config.EMAIL_PASSWORD)

                # 构建符合RFC标准的邮件
                msg = (
                    f"From: {formataddr(('天气预警系统', self.config.EMAIL_USER))}\n"
                    f"To: {self.config.RECEIVER_EMAIL}\n"
                    f"Subject: =?utf-8?b?{Header(subject, 'utf-8').encode()}?=\n"
                    f"MIME-Version: 1.0\n"
                    f"Content-Type: text/plain; charset=utf-8\n\n"
                    f"{body}"
                )

                server.sendmail(
                    self.config.EMAIL_USER,
                    [self.config.RECEIVER_EMAIL],
                    msg.encode("utf-8")
                )
                print("✅ 邮件发送成功")
        except Exception as e:
            print(f"")


def daily_check():
    """每日天气检查任务"""
    print(f"\n{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} 开始天气检查")
    monitor = WeatherMonitor()

    try:
        # 获取并解析天气数据
        raw_data = monitor.get_weather_data()
        weather = monitor.parse_weather(raw_data)

        if not weather:
            print("⚠️ 未获取到有效天气数据")
            return

        # 预警条件判断
        alert_reasons = []
        if weather["precip_prob"] > 60:
            alert_reasons.append(f"降雨概率 {weather['precip_prob']}%")
        if any(keyword in weather["condition"] for keyword in ["雨", "雪", "雹"]):
            alert_reasons.append(weather["condition"])

        # 构建邮件内容
        email_body = (
            "【天气预报通知】\n"
            f"日期: {weather['date']}\n"
            f"天气状况: {weather['condition']}\n"
            f"温度范围: {weather['temp_range']}\n"
            f"早晨降水概率: {weather['precip_prob']}%\n"
        )

        if alert_reasons:
            email_body += f"\n⚠️ 预警原因: {'，'.join(alert_reasons)}\n建议取消晨跑！"
            subject = "恶劣天气预警通知"
        else:
            email_body += "\n✅ 天气条件适宜晨跑"
            subject = "正常天气通知"

        monitor.send_email(subject, email_body)

    except Exception as e:
        print(f"❗ 任务执行异常: {str(e)}")


if __name__ == "__main__":
    # 立即执行一次测试
    daily_check()

    # 设置每日17:30执行（北京时间）
    schedule.every().day.at("17:30").do(daily_check)

    print("天气监控服务已启动...")
    try:
        while True:
            schedule.run_pending()
            time.sleep(60)
    except KeyboardInterrupt:
        print("\n服务已停止")